# A generic stack class
# Ben Terris
# 11/20/2007

class Stack:
	"""A generic stack class. Objects are pushed onto the stack and can be popped off two at a time."""

	def __init__(self):
		"""Initialize a Stack. The stack grows upwards with the newest elements placed at the bottom."""
		# Initialize the stack as an empty Python list.
		self._elements = []
		self._elementCount = 0
		return
		
	def getNumElements(self):
		"""Get the current number of elements contained in the stack."""
		return self._elementCount
	
	def getElement(self, index):
		"""Get the current element at a given index in the stack."""
		try:
			return self._elements[index]
		except:
			return None
		
	
	def push(self, operand):
		"""Push an operand onto the stack."""
		# append the operand to the end of the list
		
		self._elements.append(operand)
		self._elementCount = len(self._elements)
		
	
	def pop2(self):
		"""Pop 2 objects off the stack."""
		# create and return a new list containing the 2 popped operands
		self._elementCount = len(self._elements) - 2
		return [ self._elements.pop(), self._elements.pop() ]

        def pop(self):
                """Pop a single object off the stack."""
                self._elementCount = len(self._elements) -1
                return self._elements.pop()
		 
	def peek(self):
		"""Peek at the operand at the bottom of the stack without removing it."""
		if self._elementCount > 0:
			return self._elements[-1]
		else:
			return None
			
	def exchange(self):
		"""Exchange the bottom 2 operands"""
		ls = self._elements	
		ls[-2], ls[-1] = ls[-1], ls[-2]
		
			
	def rollUp(self):
		"""Roll the stack up, moving the top operand to the bottom."""	
		temp = self._elements[0]
		self._elements = self._elements[1:]
		self._elements.append(temp)
	
	def rollDown(self):
		"""Roll the stack down, moving the bottom operand to the top."""	
		temp = self._elements[-1]
		self._elements = self._elements[:-1]
		self._elements.insert(0, temp)
	
	def pushUp(self):
		"""Move the stack up, leaving a copy of the bottom operand in place."""	
		self.push(self.peek())

if __name__ == '__main__':
	# run a battery of unit tests to ensure correct functionality
	x = Stack()
	
	def unittests():
		'''
	>>> x.push(1)
	>>> x.push(2)
	>>> x.push(3)
	>>> x.push("test")
	>>> x.push("element")
	>>> print "top element:", x.peek()
	top element: element
	
	>>> print "stack count:", x.getNumElements()
	stack count: 5
	
	Verify top 2 elements
	>>> print x._elements[-2]
	test
	>>> print x._elements[-1]
	element
	
	
	>>> x.exchange()
	
	Show that exchange worked
	>>> print x._elements[-2]
	element
	>>> print x._elements[-1]
	test
	
	
	Pop the correct elements and update stack count
	>>> x.pop2()
	['test', 'element']
	>>> x.getNumElements()
	3
	
	Roll up the stack
	>>> x.rollUp()
	>>> x._elements[0]
	2
	>>> x._elements[1]
	3
	>>> x._elements[2]
	1
	
	Roll down the stack
	>>> x.rollDown()
	>>> x._elements[0]
	1
	>>> x._elements[1]
	2
	>>> x._elements[2]
	3
	
	Push up the stack
	>>> x.pushUp()
	>>> x._elements[0]
	1
	>>> x._elements[1]
	2
	>>> x._elements[2]
	3
	>>> x._elements[3]
	3
	
	'''



	from doctest import testmod
	testmod(verbose=True)
